home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / mail / vacation < prev    next >
Encoding:
Text File  |  1988-04-25  |  10.9 KB  |  450 lines

  1. # This is a shell archive.  Save it in a file, remove anything before
  2. # this line, and then unpack it by entering "sh file".  Note, it may
  3. # create directories; files and directories will be owned by you and
  4. # have default permissions.
  5. #
  6. # This archive contains:
  7. #
  8. #    vacation.1
  9. #    vacation.c
  10. #
  11. echo x - vacation.1
  12. sed 's/^X//' >vacation.1 << 'END-of-vacation.1'
  13. X.\" Copyright (c) 1985, 1987 Regents of the University of California.
  14. X.\" All rights reserved.
  15. X.\"
  16. X.\" Redistribution and use in source and binary forms are permitted
  17. X.\" provided that this notice is preserved and that due credit is given
  18. X.\" to the University of California at Berkeley. The name of the University
  19. X.\" may not be used to endorse or promote products derived from this
  20. X.\" software without specific prior written permission. This software
  21. X.\" is provided ``as is'' without express or implied warranty.
  22. X.\"
  23. X.\"    @(#)vacation.1    6.5 (Berkeley) 12/26/87
  24. X.\"
  25. X.TH VACATION 1 "December 26, 1987"
  26. X.UC 6
  27. X.SH NAME
  28. Xvacation \- return ``I am not here'' indication
  29. X.SH SYNOPSIS
  30. X.B vacation
  31. X.B -i
  32. X.br
  33. X.B vacation
  34. X[
  35. X.B -a
  36. Xalias ] login
  37. X.SH DESCRIPTION
  38. X\fIVacation\fP returns a message to the sender of a message telling
  39. Xthem that you are currently not reading your mail.  The intended use
  40. Xis in a \fI.forward\fP file.  For example, your \fI.forward\fP file
  41. Xmight have:
  42. X.PP
  43. X.ti +5
  44. X\eeric, "|/usr/ucb/vacation -a allman eric"
  45. X.PP
  46. Xwhich would send messages to you (assuming your login name was eric) and
  47. Xreply to any messages for ``eric'' or ``allman''.
  48. X.PP
  49. XNo message will be sent unless \fIlogin\fP or an \fIalias\fP supplied
  50. Xusing the \fB-a\fP option is a substring of either the ``To:'' or ``Cc:''
  51. Xheaders of the mail.  No messages from ``???-REQUEST'', ``Postmaster'',
  52. X``UUCP'', ``MAILER'', or ``MAILER-DAEMON'' will be replied to, nor is a
  53. Xnotification sent if a ``Precedence: bulk'' or ``Precedence: junk'' line
  54. Xis included in the mail headers.  Only one message per week will be sent
  55. Xto each unique sender.  The people who have sent you messages are
  56. Xmaintained as an \fIndbm\fP(3) database in the files \fI.vacation.pag\fP
  57. Xand \fI.vacation.dir\fP in your home directory.
  58. X.PP
  59. XThe \fB-i\fP flag initializes the vacation database files.  It should be
  60. Xused before you modify your \fI.forward\fP file.
  61. X.PP
  62. X\fIVacation\fP expects a file \fI.vacation.msg\fP, in your home directory,
  63. Xcontaining a message to be sent back to each sender.  It should be an entire
  64. Xmessage (including headers).  For example, it might say:
  65. X.PP
  66. X.in +5
  67. X.nf
  68. XFrom: eric@ucbmonet.Berkeley.EDU (Eric Allman)
  69. XSubject: I am on vacation
  70. XDelivered-By-The-Graces-Of: The Vacation program
  71. XPrecedence: bulk
  72. X
  73. XI am on vacation until July 22.  If you have something urgent,
  74. Xplease contact Joe Kalash <kalash@ucbingres.Berkeley.EDU>.
  75. X    --eric
  76. X.fi
  77. X.in -5
  78. X.PP
  79. X\fIVacation\fP reads the first line from the standard input for
  80. Xa \s-1UNIX\s0-style ``From'' line to determine the sender.
  81. X\fISendmail\fP(8) includes this ``From'' line automatically.
  82. X.PP
  83. XFatal errors, such as calling \fIvacation\fP with incorrect arguments,
  84. Xor with non-existent \fIlogin\fPs, are logged in the system log file,
  85. Xusing \fIsyslog\fP(8).
  86. X.SH FILES
  87. X.nf
  88. X.ta \w'~/.vacation.msg    'u
  89. X~/.vacation.dir    database file
  90. X~/.vacation.msg    message to send
  91. X~/.vacation.pag    database file
  92. X.fi
  93. X.SH "SEE ALSO"
  94. Xsendmail(8), syslog(8)
  95. END-of-vacation.1
  96. echo x - vacation.c
  97. sed 's/^X//' >vacation.c << 'END-of-vacation.c'
  98. X/*
  99. X * Copyright (c) 1983, 1987 Regents of the University of California.
  100. X * All rights reserved.
  101. X *
  102. X * Redistribution and use in source and binary forms are permitted
  103. X * provided that this notice is preserved and that due credit is given
  104. X * to the University of California at Berkeley. The name of the University
  105. X * may not be used to endorse or promote products derived from this
  106. X * software without specific prior written permission. This software
  107. X * is provided ``as is'' without express or implied warranty.
  108. X */
  109. X
  110. X#ifndef lint
  111. Xchar copyright[] =
  112. X"@(#) Copyright (c) 1983, 1987 Regents of the University of California.\n\
  113. X All rights reserved.\n";
  114. X#endif /* not lint */
  115. X
  116. X#ifndef lint
  117. Xstatic char sccsid[] = "@(#)vacation.c    5.9 (Berkeley) 3/24/88";
  118. X#endif /* not lint */
  119. X
  120. X/*
  121. X**  Vacation
  122. X**  Copyright (c) 1983  Eric P. Allman
  123. X**  Berkeley, California
  124. X*/
  125. X
  126. X#include <sys/param.h>
  127. X#include <sys/file.h>
  128. X#include <pwd.h>
  129. X#include <stdio.h>
  130. X#include <ctype.h>
  131. X#include <syslog.h>
  132. X
  133. X/*
  134. X**  VACATION -- return a message to the sender when on vacation.
  135. X**
  136. X**    This program could be invoked as a message receiver when someone is
  137. X**    on vacation.  It returns a message specified by the user to whoever
  138. X**    sent the mail, taking care not to return a message too often to
  139. X**    prevent "I am on vacation" loops.
  140. X*/
  141. X
  142. X#define    MAXLINE    500            /* max line from mail header */
  143. X#define    PERIOD    (60L*60L*24L*7L)    /* week between notifications */
  144. X#define    VMSG    ".vacation.msg"        /* vacation message */
  145. X#define    VACAT    ".vacation"        /* dbm's database prefix */
  146. X#define    VDIR    ".vacation.dir"        /* dbm's DB prefix, part 1 */
  147. X#define    VPAG    ".vacation.pag"        /* dbm's DB prefix, part 2 */
  148. X
  149. Xtypedef struct alias {
  150. X    struct alias *next;
  151. X    char    *name;
  152. X} ALIAS;
  153. XALIAS    *names;
  154. X
  155. Xstatic char from[MAXLINE];        /* sender's address */
  156. X
  157. Xmain(argc, argv)
  158. X    int argc;
  159. X    char **argv;
  160. X{
  161. X    extern int optind;
  162. X    extern char *optarg;
  163. X    struct passwd *pw;
  164. X    ALIAS *cur;
  165. X    int ch, iflag;
  166. X    char *malloc();
  167. X    uid_t getuid();
  168. X
  169. X    iflag = 0;
  170. X    while ((ch = getopt(argc, argv, "a:Ii")) != EOF)
  171. X        switch((char)ch) {
  172. X        case 'a':            /* alias */
  173. X            if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
  174. X                break;
  175. X            cur->name = optarg;
  176. X            cur->next = names;
  177. X            names = cur;
  178. X            break;
  179. X        case 'i':            /* init the database */
  180. X        case 'I':            /* backward compatible */
  181. X            iflag = 1;
  182. X            break;
  183. X        case '?':
  184. X        default:
  185. X            goto usage;
  186. X        }
  187. X    argc -= optind;
  188. X    argv += optind;
  189. X
  190. X    if (argc != 1) {
  191. X        if (!iflag) {
  192. Xusage:            syslog(LOG_ERR, "uid %u: usage: vacation [-i] [-a alias] login\n", getuid());
  193. X            exit(1);
  194. X        }
  195. X        if (!(pw = getpwuid(getuid()))) {
  196. X            syslog(LOG_ERR, "vacation: no such user uid %u.\n", getuid());
  197. X            exit(1);
  198. X        }
  199. X    }
  200. X    else if (!(pw = getpwnam(*argv))) {
  201. X        syslog(LOG_ERR, "vacation: no such user %s.\n", *argv);
  202. X        exit(1);
  203. X    }
  204. X    if (chdir(pw->pw_dir)) {
  205. X        syslog(LOG_ERR, "vacation: no such directory %s.\n", pw->pw_dir);
  206. X        exit(1);
  207. X    }
  208. X
  209. X    if (iflag) {
  210. X        initialize();
  211. X        exit(0);
  212. X    }
  213. X
  214. X    if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
  215. X        exit(1);
  216. X    cur->name = pw->pw_name;
  217. X    cur->next = names;
  218. X    names = cur;
  219. X
  220. X    readheaders();
  221. X
  222. X    if (access(VDIR, F_OK))
  223. X        initialize();
  224. X    else
  225. X        dbminit(VACAT);
  226. X
  227. X    if (!recent()) {
  228. X        setreply();
  229. X        sendmessage(pw->pw_name);
  230. X    }
  231. X    exit(0);
  232. X}
  233. X
  234. X/*
  235. X * readheaders --
  236. X *    read mail headers
  237. X */
  238. Xstatic
  239. Xreadheaders()
  240. X{
  241. X    register ALIAS *cur;
  242. X    register char *p;
  243. X    int tome, cont;
  244. X    char buf[MAXLINE], *strcpy(), *index();
  245. X
  246. X    cont = tome = 0;
  247. X    while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
  248. X        switch(*buf) {
  249. X        case 'F':        /* "From " */
  250. X            cont = 0;
  251. X            if (!strncmp(buf, "From ", 5)) {
  252. X                for (p = buf + 5; *p && *p != ' '; ++p);
  253. X                *p = '\0';
  254. X                (void)strcpy(from, buf + 5);
  255. X                if (junkmail())
  256. X                    exit(0);
  257. X            }
  258. X            break;
  259. X        case 'P':        /* "Precedence:" */
  260. X            cont = 0;
  261. X            if (strncasecmp(buf, "Precedence", 10) || buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t')
  262. X                break;
  263. X            if (!(p = index(buf, ':')))
  264. X                break;
  265. X            while (*++p && isspace(*p));
  266. X            if (!*p)
  267. X                break;
  268. X            if (!strncasecmp(p, "junk", 4) || !strncasecmp(p, "bulk", 4))
  269. X                exit(0);
  270. X            break;
  271. X        case 'C':        /* "Cc:" */
  272. X            if (strncmp(buf, "Cc:", 3))
  273. X                break;
  274. X            cont = 1;
  275. X            goto findme;
  276. X        case 'T':        /* "To:" */
  277. X            if (strncmp(buf, "To:", 3))
  278. X                break;
  279. X            cont = 1;
  280. X            goto findme;
  281. X        default:
  282. X            if (!isspace(*buf) || !cont || tome) {
  283. X                cont = 0;
  284. X                break;
  285. X            }
  286. Xfindme:            for (cur = names; !tome && cur; cur = cur->next)
  287. X                tome += nsearch(cur->name, buf);
  288. X        }
  289. X    if (!tome)
  290. X        exit(0);
  291. X    if (!*from) {
  292. X        syslog(LOG_ERR, "vacation: no initial \"From\" line.\n");
  293. X        exit(1);
  294. X    }
  295. X}
  296. X
  297. X/*
  298. X * nsearch --
  299. X *    do a nice, slow, search of a string for a substring.
  300. X */
  301. Xstatic
  302. Xnsearch(name, str)
  303. X    register char *name, *str;
  304. X{
  305. X    register int len;
  306. X
  307. X    for (len = strlen(name); *str; ++str)
  308. X        if (*str == *name && !strncasecmp(name, str, len))
  309. X            return(1);
  310. X    return(0);
  311. X}
  312. X
  313. X/*
  314. X * junkmail --
  315. X *    read the header and return if automagic/junk/bulk mail
  316. X */
  317. Xstatic
  318. Xjunkmail()
  319. X{
  320. X    static struct ignore {
  321. X        char    *name;
  322. X        int    len;
  323. X    } ignore[] = {
  324. X        "-REQUEST", 8,    "Postmaster", 10,
  325. X        "uucp", 4,    "MAILER-DAEMON", 13,
  326. X        "MAILER", 6,    NULL, NULL,
  327. X    };
  328. X    register struct ignore *cur;
  329. X    register int len;
  330. X    register char *p;
  331. X    char *index(), *rindex();
  332. X
  333. X    /*
  334. X     * This is mildly amusing, and I'm not positive it's right; trying
  335. X     * to find the "real" name of the sender, assuming that addresses
  336. X     * will be some variant of:
  337. X     *
  338. X     * From site!site!SENDER%site.domain%site.domain@site.domain
  339. X     */
  340. X    if (!(p = index(from, '%')))
  341. X        if (!(p = index(from, '@'))) {
  342. X            if (p = rindex(from, '!'))
  343. X                ++p;
  344. X            else
  345. X                p = from;
  346. X            for (; *p; ++p);
  347. X        }
  348. X    len = p - from;
  349. X    for (cur = ignore; cur->name; ++cur)
  350. X        if (len >= cur->len && !strncasecmp(cur->name, p - cur->len, cur->len))
  351. X            return(1);
  352. X    return(0);
  353. X}
  354. X
  355. Xtypedef struct {
  356. X    char    *dptr;
  357. X    int    dsize;
  358. X} DATUM;
  359. X
  360. Xtypedef struct {
  361. X    time_t    sentdate;
  362. X} DBREC;
  363. X
  364. X/*
  365. X * recent --
  366. X *    find out if user has gotten a vacation message recently.
  367. X */
  368. Xstatic
  369. Xrecent()
  370. X{
  371. X    DATUM k, d, fetch();
  372. X    time_t now, then, time();
  373. X
  374. X    k.dptr = from;
  375. X    k.dsize = strlen(from) + 1;
  376. X    d = fetch(k);
  377. X    if (d.dptr) {
  378. X        /* be careful on machines with alignment restrictions */
  379. X        bcopy((char *)&((DBREC *)d.dptr)->sentdate, (char *)&then, sizeof(then));
  380. X        (void)time(&now);
  381. X        if (!then || then + PERIOD > now)
  382. X            return(1);
  383. X    }
  384. X    return(0);
  385. X}
  386. X
  387. X/*
  388. X * setreply --
  389. X *    store that this user knows about the vacation.
  390. X */
  391. Xstatic
  392. Xsetreply()
  393. X{
  394. X    DBREC xrec;
  395. X    DATUM k, d;
  396. X    time_t time();
  397. X
  398. X    k.dptr = from;
  399. X    k.dsize = strlen(from) + 1;
  400. X    (void)time(&xrec.sentdate);
  401. X    d.dptr = (char *)&xrec;
  402. X    d.dsize = sizeof(xrec);
  403. X    store(k, d);
  404. X}
  405. X
  406. X/*
  407. X * sendmessage --
  408. X *    exec sendmail to send the vacation file to sender
  409. X */
  410. Xstatic
  411. Xsendmessage(myname)
  412. X    char *myname;
  413. X{
  414. X    if (!freopen(VMSG, "r", stdin)) {
  415. X        syslog(LOG_ERR, "vacation: no ~%s/%s file.\n", myname, VMSG);
  416. X        exit(1);
  417. X    }
  418. X    execl("/usr/lib/sendmail", "sendmail", "-f", myname, from, NULL);
  419. X    syslog(LOG_ERR, "vacation: can't exec /usr/lib/sendmail.\n");
  420. X    exit(1);
  421. X}
  422. X
  423. X/*
  424. X * initialize --
  425. X *    initialize the dbm database
  426. X */
  427. Xstatic
  428. Xinitialize()
  429. X{
  430. X    extern int errno;
  431. X    extern char *sys_errlist[];
  432. X    int fd;
  433. X
  434. X    if ((fd = open(VDIR, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
  435. X        syslog(LOG_ERR, "vacation: %s: %s\n", VDIR, sys_errlist[errno]);
  436. X        exit(1);
  437. X    }
  438. X    (void)close(fd);
  439. X    if ((fd = open(VPAG, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
  440. X        syslog(LOG_ERR, "vacation: %s: %s\n", VPAG, sys_errlist[errno]);
  441. X        exit(1);
  442. X    }
  443. X    (void)close(fd);
  444. X    dbminit(VACAT);
  445. X}
  446. END-of-vacation.c
  447. exit
  448.  
  449.  
  450.